package com.jinmdz.fmis.api.admin.service;

import com.jinmdz.fmis.api.admin.model.rolerelation.*;
import com.jinmdz.fmis.api.api.model.common.IdVersionData;
import com.jinmdz.fmis.api.base.BaseService;
import com.jinmdz.fmis.api.model.config.dictionary.OperationLogCode;
import com.jinmdz.fmis.api.model.system.UserItem;
import com.jinmdz.fmis.api.wrapper.DictionaryWrapper;
import com.jinmdz.fmis.api.wrapper.OperationWrapper;
import com.jinmdz.fmis.common.ext.StringBuilderExt;
import com.jinmdz.fmis.common.util.BeanUtil;
import com.jinmdz.fmis.common.util.DataUtil;
import com.jinmdz.fmis.core.base.BaseResult;
import com.jinmdz.fmis.core.exception.ActionException;
import com.jinmdz.fmis.core.util.JacksonUtil;
import com.jinmdz.fmis.dao.admin.dao.AccountUserDao;
import com.jinmdz.fmis.dao.admin.dao.RoleDao;
import com.jinmdz.fmis.dao.admin.dao.RoleRelationDao;
import com.jinmdz.fmis.dao.admin.model.accountuser.AccountUserEditItem;
import com.jinmdz.fmis.dao.admin.model.role.RoleEditItem;
import com.jinmdz.fmis.dao.admin.model.rolerelation.RoleMenuButtonListItem;
import com.jinmdz.fmis.dao.admin.model.rolerelation.RoleMenuListItem;
import com.jinmdz.fmis.dao.admin.model.rolerelation.RoleUserListItem;
import com.jinmdz.fmis.mapper.entity.RoleMenuButtonRelationEntity;
import com.jinmdz.fmis.mapper.entity.RoleMenuRelationEntity;
import com.jinmdz.fmis.mapper.entity.RoleUserRelationEntity;
import com.jinmdz.fmis.mapper.mapper.RoleMenuButtonRelationMapper;
import com.jinmdz.fmis.mapper.mapper.RoleMenuRelationMapper;
import com.jinmdz.fmis.mapper.mapper.RoleUserRelationMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;

/**
 * 角色关联Service
 *
 * @author LiCongLu
 * @date 2020-03-19 10:17
 */
@Service("roleRelationService")
public class RoleRelationService extends BaseService {

    @Resource
    private DictionaryWrapper dictionaryWrapper;

    @Resource
    private RoleRelationDao roleRelationDao;

    @Resource
    private OperationWrapper operationWrapper;

    @Resource
    private OperationLogCode operationLogCode;

    @Resource
    private AccountUserDao accountUserDao;

    @Resource
    private RoleUserRelationMapper roleUserRelationMapper;

    @Resource
    private RoleMenuRelationMapper roleMenuRelationMapper;

    @Resource
    private RoleMenuButtonRelationMapper roleMenuButtonRelationMapper;

    @Resource
    private RoleDao roleDao;

    /**
     * 根据角色id加载角色下包含的用户数据
     *
     * @param data 角色主键
     * @return
     * @author LiCongLu
     * @date 2020-03-19 10:21
     */
    public BaseResult<ArrayList<RoleUserListItem>> loadRoleUserWithRoleId(BusinessSystemRoleIdData data) {
        ArrayList<RoleUserListItem> loadItems = roleRelationDao.listRoleUserByRoleId(data.getBusinessSystemRoleId());
        // 设置字典文本
        dictionaryWrapper.resetDataText(loadItems);
        return successList(loadItems);
    }

    /**
     * 保存角色用户关联信息
     *
     * @param data 角色与用户关联信息
     * @return
     * @author LiCongLu
     * @date 2020-03-18 17:26
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveRoleUserRelation(UserItem userItem, ArrayList<RoleUserRelationSaveData> data) throws ActionException {
        // 判断类型
        if (DataUtil.invalid(data)) {
            throw exception("角色用户关联信息不能为空！");
        }

        // 记录新增角色用户关联信息
        ArrayList<RoleUserRelationEntity> relationEntities = new ArrayList<>();

        // 记录businessSystemRoleId
        Integer businessSystemRoleId = data.get(0).getBusinessSystemRoleId();

        // 遍历追加
        for (RoleUserRelationSaveData saveData : data) {
            // 验证用户帐号
            AccountUserEditItem accountUserEditItem = accountUserDao.getAccountUserEditById(saveData.getSystemUserId());
            if (DataUtil.isNull(accountUserEditItem) || DataUtil.isNull(accountUserEditItem.getId(), accountUserEditItem.getVersion())) {
                throw exception("存在无效关联员工");
            }

            // 创建实体
            RoleUserRelationEntity entity = getEntity(userItem, RoleUserRelationEntity.class);
            entity.setBusinessSystemRoleId(businessSystemRoleId)
                    .setSystemUserId(saveData.getSystemUserId());

            // 判断角色用户关联信息的重复性
            Integer roleRelationId = roleRelationDao.getRoleRelationIdByUserId(entity.getBusinessSystemRoleId(), entity.getSystemUserId());
            if (DataUtil.valid(roleRelationId)) {
                // 当已存在关联关系时，继续循环而不进行跳转
                continue;
            }

            // 新增角色用户关联信息
            roleUserRelationMapper.insertRoleUserRelation(entity);
            // 判断保存角色用户关联信息结果
            if (DataUtil.invalid(entity.getId())) {
                throw exception("保存角色用户关联信息失败");
            }

            // 记录新增数据
            relationEntities.add(entity);
        }

        // 添加操作日志
        saveRoleUserRelationLog(userItem, operationLogCode.getInsert(), data, relationEntities);

        return success("保存成功");
    }

    /**
     * 添加修改记录
     *
     * @param userItem         当前帐号
     * @param logTypeCode      操作日志值
     * @param data             请求数据
     * @param relationEntities 新增实体
     * @return
     * @author LiCongLu
     * @date 2020-03-17 14:18
     */
    private void saveRoleUserRelationLog(UserItem userItem, Integer logTypeCode, ArrayList<RoleUserRelationSaveData> data, ArrayList<RoleUserRelationEntity> relationEntities) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("保存角色用户关联信息，关联个数[{0}]，操作人员[{1}]", String.valueOf(relationEntities.size()), userItem.getFullName());

        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), null, JacksonUtil.obj2Json(relationEntities));
    }

    /**
     * 删除角色与用户关联关系
     *
     * @param data 主键和数据版本号
     * @return
     * @author LiCongLu
     * @date 2020-03-19 10:37
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult deleteRoleUserRelationWithId(UserItem userItem, ArrayList<IdVersionData> data) throws ActionException {
        // 判断删除主键集合是否存在
        if (DataUtil.invalid(data)) {
            throw exception("不存在要删除的关联信息");
        }

        // 验证主键是否重复
        if (data.size() != getRepeatIdSize(data)) {
            throw exception("关联主键存在重复");
        }

        // 记录角色用户关联信息集合
        ArrayList<RoleUserListItem> loadItems = new ArrayList<>();

        // 进行遍历删除信息
        for (IdVersionData idData : data) {
            // 通过主键查询职员用户信息
            RoleUserListItem loadItem = roleRelationDao.getRoleUserById(idData.getId());
            if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getRoleUserRelationId(), loadItem.getVersion())) {
                throw exception("主键错误，不存在角色用户关联信息");
            }

            // 验证信息版本
            if (!DataUtil.equals(loadItem.getVersion(), idData.getVersion())) {
                throw exception(versionError("角色用户关联信息"));
            }

            // 删除关联信息
            roleUserRelationMapper.deletedForRoleUserRelation(loadItem.getRoleUserRelationId(), userItem.getId(), loadItem.getVersion());
            // 记录用户信息
            loadItems.add(loadItem);
        }

        // 添加操作日志信息
        deleteRoleUserRelationLog(userItem, operationLogCode.getDelete(), data, loadItems);

        return success("删除成功");
    }

    /**
     * 添加修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @param loadItems   删除信息实体
     * @return
     * @author LiCongLu
     * @date 2020-03-19 11:07
     */
    private void deleteRoleUserRelationLog(UserItem userItem, Integer logTypeCode, ArrayList<IdVersionData> data, ArrayList<RoleUserListItem> loadItems) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("删除帐号角色用户关联用户信息，操作人员[{1}]", userItem.getFullName());
        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), JacksonUtil.obj2Json(loadItems), null);
    }

    /**
     * 根据角色id加载角色下包含的菜单数据和按钮数据
     *
     * @param data 角色主键
     * @return
     * @author LiCongLu
     * @date 2020-03-19 11:26
     */
    public BaseResult<ArrayList<RoleMenuTableData>> loadRoleMenuButtonWithRoleId(RoleMenuButtonRoleIdData data) {
        // 查询信息
        RoleEditItem loadItem = roleDao.getRoleEditById(data.getBusinessSystemRoleId());
        if (DataUtil.isNull(loadItem) || DataUtil.isNull(loadItem.getId(), loadItem.getVersion())) {
            return failure("角色主键错误，不存在此角色信息");
        }

        // 判断系统主键
        if (!DataUtil.equals(data.getBusinessSystemId(), loadItem.getBusinessSystemId())) {
            return failure("系统主键错误，角色所属系统非此系统");
        }

        // 返回数据结果
        ArrayList<RoleMenuTableData> loadData = new ArrayList<>();

        // 获取菜单
        ArrayList<RoleMenuListItem> menuListItems = roleRelationDao.listRoleMenuListBySystemId(data.getBusinessSystemId(), data.getBusinessSystemRoleId());
        // 获取按钮
        ArrayList<RoleMenuButtonListItem> buttonListItems = roleRelationDao.listRoleMenuButtonListBySystemId(data.getBusinessSystemId(), data.getBusinessSystemRoleId());

        // 遍历获取返回结构
        for (RoleMenuListItem menuListItem : menuListItems) {
            RoleMenuTableData menuTableData = BeanUtil.copy2Bean(menuListItem, new RoleMenuTableData());
            ArrayList<RoleMenuButtonTableData> buttons = new ArrayList<>();
            for (RoleMenuButtonListItem buttonListItem : buttonListItems) {
                if (DataUtil.equals(buttonListItem.getBusinessSystemMenuId(), menuListItem.getId())) {
                    RoleMenuButtonTableData buttonTableData = BeanUtil.copy2Bean(buttonListItem, new RoleMenuButtonTableData());
                    buttons.add(buttonTableData);
                }
            }
            menuTableData.setButtons(buttons);
            loadData.add(menuTableData);
        }
        return successList(loadData);
    }

    /**
     * 保存角色菜单按钮关联信息
     *
     * @author LiCongLu
     * @date 2020-03-19 11:29
     */
    @Transactional(rollbackFor = Exception.class)
    public BaseResult saveRoleMenuButtonRelation(UserItem userItem, RoleMenuButtonRelationSaveData data) throws ActionException {

        // 记录businessSystemRoleId
        Integer businessSystemRoleId = data.getBusinessSystemRoleId();

        // 清除原关联菜单信息
        roleRelationDao.deletedForRoleMenuRelation(businessSystemRoleId, userItem.getId());
        // 清除原关联菜单按钮信息
        roleRelationDao.deletedForRoleMenuButtonRelation(businessSystemRoleId, userItem.getId());

        // 当角色菜单关联有效时执行
        if (DataUtil.valid(data.getRoleMenuRelations())) {

            // 遍历追加菜单关联信息
            for (RoleMenuButtonRelationMenuData menuData : data.getRoleMenuRelations()) {
                // 创建实体
                RoleMenuRelationEntity entity = getEntity(userItem, RoleMenuRelationEntity.class);
                entity.setBusinessSystemRoleId(businessSystemRoleId)
                        .setBusinessSystemMenuId(menuData.getBusinessSystemMenuId());

                // 新增权限关联菜单信息
                roleMenuRelationMapper.insertRoleMenuRelation(entity);
                // 判断保存信息结果
                if (DataUtil.invalid(entity.getId())) {
                    throw exception("保存角色菜单关联信息失败");
                }
            }

            // 当角色菜单按钮有效时执行
            if (DataUtil.valid(data.getRoleMenuButtonRelations())) {
                // 遍历追加菜单按钮关联信息
                for (RoleMenuButtonRelationButtonData buttonData : data.getRoleMenuButtonRelations()) {
                    // 创建实体
                    RoleMenuButtonRelationEntity entity = getEntity(userItem, RoleMenuButtonRelationEntity.class);
                    entity.setBusinessSystemRoleId(businessSystemRoleId)
                            .setBusinessSystemMenuId(buttonData.getBusinessSystemMenuId())
                            .setBusinessSystemMenuButtonId(buttonData.getBusinessSystemMenuButtonId());

                    // 新增权限关联菜单信息
                    roleMenuButtonRelationMapper.insertRoleMenuButtonRelation(entity);
                    // 判断保存信息结果
                    if (DataUtil.invalid(entity.getId())) {
                        throw exception("保存角色菜单按钮关联信息失败");
                    }
                }
            }

            // 添加操作日志
            saveRoleMenuButtonRelationLog(userItem, operationLogCode.getInsert(), data);
        }

        return success("保存成功");
    }

    /**
     * 添加修改记录
     *
     * @param userItem    当前帐号
     * @param logTypeCode 操作日志值
     * @param data        请求数据
     * @return
     * @author LiCongLu
     * @date 2020-03-19 15:15
     */
    private void saveRoleMenuButtonRelationLog(UserItem userItem, Integer logTypeCode, RoleMenuButtonRelationSaveData data) throws ActionException {
        // 操作日志字符串
        StringBuilderExt builder = new StringBuilderExt();
        builder.format("添加角色关联菜单按钮信息，操作人员[{1}]", userItem.getFullName());
        // 添加日志
        operationWrapper.operationLog(userItem, logTypeCode, builder.toString(), JacksonUtil.obj2Json(data), null, null);
    }
}